{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Step 1: 导入使用的库"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "from transformers import AutoTokenizer, AutoModelForSequenceClassification\n",
    "import os\n",
    "from torch.utils.data import DataLoader, Dataset, random_split\n",
    "import torch\n",
    "os.environ[\"TOKENIZERS_PARALLELISM\"] = \"true\"\n",
    "data_dir = os.path.expanduser(\"~/datasets/\")\n",
    "model_dir = os.path.expanduser(\"~/models/\")\n",
    "print(os.listdir(data_dir))\n",
    "print(os.listdir(model_dir))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Step 2： 加载和处理数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>label</th>\n",
       "      <th>review</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1</td>\n",
       "      <td>距离川沙公路较近,但是公交指示不对,如果是\"蔡陆线\"的话,会非常麻烦.建议用别的路线.房间较...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1</td>\n",
       "      <td>商务大床房，房间很大，床有2M宽，整体感觉经济实惠不错!</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>1</td>\n",
       "      <td>早餐太差，无论去多少人，那边也不加食品的。酒店应该重视一下这个问题了。房间本身很好。</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>1</td>\n",
       "      <td>宾馆在小街道上，不大好找，但还好北京热心同胞很多~宾馆设施跟介绍的差不多，房间很小，确实挺小...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>1</td>\n",
       "      <td>CBD中心,周围没什么店铺,说5星有点勉强.不知道为什么卫生间没有电吹风</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   label                                             review\n",
       "0      1  距离川沙公路较近,但是公交指示不对,如果是\"蔡陆线\"的话,会非常麻烦.建议用别的路线.房间较...\n",
       "1      1                       商务大床房，房间很大，床有2M宽，整体感觉经济实惠不错!\n",
       "2      1         早餐太差，无论去多少人，那边也不加食品的。酒店应该重视一下这个问题了。房间本身很好。\n",
       "3      1  宾馆在小街道上，不大好找，但还好北京热心同胞很多~宾馆设施跟介绍的差不多，房间很小，确实挺小...\n",
       "4      1               CBD中心,周围没什么店铺,说5星有点勉强.不知道为什么卫生间没有电吹风"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data_name = r'ChineseNlpCorpus/ChnSentiCorp_htl_all/ChnSentiCorp_htl_all.csv'\n",
    "data_path = os.path.join(data_dir, data_name)\n",
    "df = pd.read_csv(data_path)\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(7766, 2)"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>label</th>\n",
       "      <th>review</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>6374</th>\n",
       "      <td>0</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "      label review\n",
       "6374      0    NaN"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df[df.isna().any(axis=1)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(7765, 2)"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df = df.dropna().reset_index(drop=True)\n",
    "df.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>label</th>\n",
       "      <th>review</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1</td>\n",
       "      <td>距离川沙公路较近,但是公交指示不对,如果是\"蔡陆线\"的话,会非常麻烦.建议用别的路线.房间较...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1</td>\n",
       "      <td>商务大床房，房间很大，床有2M宽，整体感觉经济实惠不错!</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>1</td>\n",
       "      <td>早餐太差，无论去多少人，那边也不加食品的。酒店应该重视一下这个问题了。房间本身很好。</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>1</td>\n",
       "      <td>宾馆在小街道上，不大好找，但还好北京热心同胞很多~宾馆设施跟介绍的差不多，房间很小，确实挺小...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>1</td>\n",
       "      <td>CBD中心,周围没什么店铺,说5星有点勉强.不知道为什么卫生间没有电吹风</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   label                                             review\n",
       "0      1  距离川沙公路较近,但是公交指示不对,如果是\"蔡陆线\"的话,会非常麻烦.建议用别的路线.房间较...\n",
       "1      1                       商务大床房，房间很大，床有2M宽，整体感觉经济实惠不错!\n",
       "2      1         早餐太差，无论去多少人，那边也不加食品的。酒店应该重视一下这个问题了。房间本身很好。\n",
       "3      1  宾馆在小街道上，不大好找，但还好北京热心同胞很多~宾馆设施跟介绍的差不多，房间很小，确实挺小...\n",
       "4      1               CBD中心,周围没什么店铺,说5星有点勉强.不知道为什么卫生间没有电吹风"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "label\n",
       "1    5322\n",
       "0    2443\n",
       "Name: count, dtype: int64"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.label.value_counts()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 创建dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Hotel_review_dataset(Dataset):\n",
    "    def __init__(self, data_path):\n",
    "        super().__init__()\n",
    "        self.data = pd.read_csv(data_path)\n",
    "        self.data = self.data.dropna().reset_index(drop=True)\n",
    "    \n",
    "    def __getitem__(self, index):\n",
    "        return self.data.iloc[index][\"review\"], self.data.iloc[index]['label']\n",
    "    \n",
    "    def __len__(self):\n",
    "        return self.data.shape[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "def print_dataset(dataset, k=5):\n",
    "    for index in range(k):\n",
    "        print(f\"第 {index} 条数据：{dataset[index]}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "第 0 条数据：('距离川沙公路较近,但是公交指示不对,如果是\"蔡陆线\"的话,会非常麻烦.建议用别的路线.房间较为简单.', 1)\n",
      "第 1 条数据：('商务大床房，房间很大，床有2M宽，整体感觉经济实惠不错!', 1)\n",
      "第 2 条数据：('早餐太差，无论去多少人，那边也不加食品的。酒店应该重视一下这个问题了。房间本身很好。', 1)\n",
      "第 3 条数据：('宾馆在小街道上，不大好找，但还好北京热心同胞很多~宾馆设施跟介绍的差不多，房间很小，确实挺小，但加上低价位因素，还是无超所值的；环境不错，就在小胡同内，安静整洁，暖气好足-_-||。。。呵还有一大优势就是从宾馆出发，步行不到十分钟就可以到梅兰芳故居等等，京味小胡同，北海距离好近呢。总之，不错。推荐给节约消费的自助游朋友~比较划算，附近特色小吃很多~', 1)\n",
      "第 4 条数据：('CBD中心,周围没什么店铺,说5星有点勉强.不知道为什么卫生间没有电吹风', 1)\n"
     ]
    }
   ],
   "source": [
    "dataset = Hotel_review_dataset(data_path)\n",
    "print_dataset(dataset)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 划分数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "第 0 条数据：('行政豪华间有点偏贵，房间面积小了！服务总体还可以，就是房间清扫人员不太注意礼貌，有时候刚敲门马上就擅自进来！酒店位置不错！', 1)\n",
      "第 1 条数据：('离故宫不太远，走路大概10分钟不到点，环境还好，有一点非常不好的是窗帘就只有一层，早上很早就被刺眼的阳光给折腾醒了，郁闷```', 1)\n",
      "第 2 条数据：('每次去都是住这家酒店，决定环境很棒，服务也非常到位，性价比不错，而且经常会有意外惊喜的upgrade!', 1)\n",
      "第 3 条数据：('1.前台服务人员很有礼貌与热情。2.定的是大床房，房间空间和格局不错，就是地毯有点脏，冰箱的声音晚上有点吵。3.地点对于晚上想泡酒吧的游客很适合。4.酒店周边很多不错的小饭店。5.这个价位，姑苏的信价比不错。下次还要住这里。', 1)\n",
      "第 4 条数据：('老掉牙的五星酒店，我们入住的客房窗外就是酒店的封闭露台，窗下堆放疑似废弃的棉被等物品，还好就住一天，拉上窗帘将就一夜，第二天就赶紧离店了。', 0)\n"
     ]
    }
   ],
   "source": [
    "train_dataset, val_dataset = random_split(dataset, [0.7, 0.3])\n",
    "print_dataset(val_dataset)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 创建dataloader"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "model_name = r\"hfl/rbt3\"\n",
    "model_path = os.path.join(model_dir, model_name)\n",
    "tokenizer = AutoTokenizer.from_pretrained(model_path)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "def collate_fn(batch):\n",
    "    texts, labels = [], []\n",
    "    for sample in batch:\n",
    "        texts.append(sample[0])\n",
    "        labels.append(sample[1])\n",
    "    inputs = tokenizer(texts, max_length=128, padding='max_length', truncation=True, return_tensors='pt')\n",
    "    inputs[\"labels\"] = torch.tensor(labels)\n",
    "    return inputs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "batch_size = 32\n",
    "num_workers = os.cpu_count() // 2\n",
    "train_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, drop_last=True, num_workers=num_workers, collate_fn=collate_fn)\n",
    "val_dataloader = DataLoader(val_dataset, batch_size=batch_size, num_workers=num_workers, collate_fn=collate_fn)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "batch = next(iter(val_dataloader))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'input_ids': tensor([[ 101, 6121, 3124,  ...,    0,    0,    0],\n",
       "        [ 101, 4895, 3125,  ...,    0,    0,    0],\n",
       "        [ 101, 3680, 3613,  ...,    0,    0,    0],\n",
       "        ...,\n",
       "        [ 101, 6983, 2421,  ...,    0,    0,    0],\n",
       "        [ 101, 2769, 3221,  ...,    0,    0,    0],\n",
       "        [ 101, 6983, 2421,  ...,    0,    0,    0]]), 'token_type_ids': tensor([[0, 0, 0,  ..., 0, 0, 0],\n",
       "        [0, 0, 0,  ..., 0, 0, 0],\n",
       "        [0, 0, 0,  ..., 0, 0, 0],\n",
       "        ...,\n",
       "        [0, 0, 0,  ..., 0, 0, 0],\n",
       "        [0, 0, 0,  ..., 0, 0, 0],\n",
       "        [0, 0, 0,  ..., 0, 0, 0]]), 'attention_mask': tensor([[1, 1, 1,  ..., 0, 0, 0],\n",
       "        [1, 1, 1,  ..., 0, 0, 0],\n",
       "        [1, 1, 1,  ..., 0, 0, 0],\n",
       "        ...,\n",
       "        [1, 1, 1,  ..., 0, 0, 0],\n",
       "        [1, 1, 1,  ..., 0, 0, 0],\n",
       "        [1, 1, 1,  ..., 0, 0, 0]]), 'labels': tensor([1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1,\n",
       "        1, 1, 1, 0, 1, 1, 0, 0])}"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "batch"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Step 3： 创建模型和优化器等"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Some weights of BertForSequenceClassification were not initialized from the model checkpoint at /home/sxliu/models/hfl/rbt3 and are newly initialized: ['classifier.bias', 'classifier.weight']\n",
      "You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.\n"
     ]
    }
   ],
   "source": [
    "model = AutoModelForSequenceClassification.from_pretrained(model_path, id2label={0: \"差评\", 1: \"好评\"}, num_labels = 2)\n",
    "optimazer = torch.optim.Adam(model.parameters(), lr=2e-5, weight_decay=1e-6)\n",
    "model = model.cuda()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "BertConfig {\n",
       "  \"_attn_implementation_autoset\": true,\n",
       "  \"_name_or_path\": \"/home/sxliu/models/hfl/rbt3\",\n",
       "  \"architectures\": [\n",
       "    \"BertForMaskedLM\"\n",
       "  ],\n",
       "  \"attention_probs_dropout_prob\": 0.1,\n",
       "  \"classifier_dropout\": null,\n",
       "  \"directionality\": \"bidi\",\n",
       "  \"hidden_act\": \"gelu\",\n",
       "  \"hidden_dropout_prob\": 0.1,\n",
       "  \"hidden_size\": 768,\n",
       "  \"id2label\": {\n",
       "    \"0\": \"\\u5dee\\u8bc4\",\n",
       "    \"1\": \"\\u597d\\u8bc4\"\n",
       "  },\n",
       "  \"initializer_range\": 0.02,\n",
       "  \"intermediate_size\": 3072,\n",
       "  \"layer_norm_eps\": 1e-12,\n",
       "  \"max_position_embeddings\": 512,\n",
       "  \"model_type\": \"bert\",\n",
       "  \"num_attention_heads\": 12,\n",
       "  \"num_hidden_layers\": 3,\n",
       "  \"output_past\": true,\n",
       "  \"pad_token_id\": 0,\n",
       "  \"pooler_fc_size\": 768,\n",
       "  \"pooler_num_attention_heads\": 12,\n",
       "  \"pooler_num_fc_layers\": 3,\n",
       "  \"pooler_size_per_head\": 128,\n",
       "  \"pooler_type\": \"first_token_transform\",\n",
       "  \"position_embedding_type\": \"absolute\",\n",
       "  \"problem_type\": \"single_label_classification\",\n",
       "  \"transformers_version\": \"4.46.1\",\n",
       "  \"type_vocab_size\": 2,\n",
       "  \"use_cache\": true,\n",
       "  \"vocab_size\": 21128\n",
       "}"
      ]
     },
     "execution_count": 65,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model.config"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [],
   "source": [
    "epochs = 20\n",
    "\n",
    "def evaluate():\n",
    "    model.eval()\n",
    "    acc_num = 0\n",
    "    with torch.inference_mode():\n",
    "        for batch in val_dataloader:\n",
    "            if torch.cuda.is_available():\n",
    "                batch = {k: v.cuda() for k, v in batch.items()}\n",
    "            outputs = model(**batch)\n",
    "            pred = torch.argmax(outputs.logits, dim=-1)\n",
    "            acc_num += (pred.long() == batch[\"labels\"].long()).float().sum()\n",
    "    return acc_num / len(val_dataset)\n",
    "\n",
    "def train(epochs, log_step=100):\n",
    "    global_step = 0\n",
    "    for epoch in range(epochs):\n",
    "        model.train()\n",
    "        for batch in train_dataloader:\n",
    "            batch = {k: v.cuda() for k, v in batch.items()}\n",
    "            optimazer.zero_grad()\n",
    "            outputs = model(**batch)\n",
    "            outputs.loss.backward()\n",
    "            optimazer.step()\n",
    "\n",
    "            if global_step % log_step == 0:\n",
    "                print(f\"##epoch {epoch} loss is {outputs.loss.item():.4f}\")\n",
    "\n",
    "            global_step += 1\n",
    "        acc = evaluate()\n",
    "        print(f\"##epoch {epoch} val acc is {acc:.4f}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "##epoch 0 loss is 0.0132\n",
      "##epoch 0 loss is 0.0063\n",
      "##epoch 0 val acc is 0.9034\n",
      "##epoch 1 loss is 0.0103\n",
      "##epoch 1 loss is 0.0076\n",
      "##epoch 1 val acc is 0.8909\n",
      "##epoch 2 loss is 0.0097\n",
      "##epoch 2 loss is 0.0081\n",
      "##epoch 2 val acc is 0.8991\n",
      "##epoch 3 loss is 0.0392\n",
      "##epoch 3 val acc is 0.8918\n",
      "##epoch 4 loss is 0.0309\n",
      "##epoch 4 loss is 0.0080\n",
      "##epoch 4 val acc is 0.8974\n",
      "##epoch 5 loss is 0.0067\n",
      "##epoch 5 loss is 0.0006\n",
      "##epoch 5 val acc is 0.8952\n",
      "##epoch 6 loss is 0.0003\n",
      "##epoch 6 val acc is 0.9000\n",
      "##epoch 7 loss is 0.0266\n",
      "##epoch 7 loss is 0.0012\n",
      "##epoch 7 val acc is 0.9004\n",
      "##epoch 8 loss is 0.0008\n",
      "##epoch 8 loss is 0.0003\n",
      "##epoch 8 val acc is 0.8978\n",
      "##epoch 9 loss is 0.0006\n",
      "##epoch 9 val acc is 0.9008\n",
      "##epoch 10 loss is 0.0797\n",
      "##epoch 10 loss is 0.0029\n",
      "##epoch 10 val acc is 0.8970\n",
      "##epoch 11 loss is 0.0007\n",
      "##epoch 11 loss is 0.0093\n",
      "##epoch 11 val acc is 0.8914\n",
      "##epoch 12 loss is 0.0019\n",
      "##epoch 12 val acc is 0.8987\n",
      "##epoch 13 loss is 0.0003\n",
      "##epoch 13 loss is 0.0002\n",
      "##epoch 13 val acc is 0.8995\n",
      "##epoch 14 loss is 0.0162\n",
      "##epoch 14 loss is 0.0002\n",
      "##epoch 14 val acc is 0.8987\n",
      "##epoch 15 loss is 0.0024\n",
      "##epoch 15 loss is 0.0005\n",
      "##epoch 15 val acc is 0.8948\n",
      "##epoch 16 loss is 0.0003\n",
      "##epoch 16 val acc is 0.9038\n",
      "##epoch 17 loss is 0.0001\n",
      "##epoch 17 loss is 0.0358\n",
      "##epoch 17 val acc is 0.8987\n",
      "##epoch 18 loss is 0.0003\n",
      "##epoch 18 loss is 0.0007\n",
      "##epoch 18 val acc is 0.9030\n",
      "##epoch 19 loss is 0.0947\n",
      "##epoch 19 val acc is 0.8987\n"
     ]
    }
   ],
   "source": [
    "train(epochs, log_step=100)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "输入: 包装压坏了，里面的东西也坏了，怎么办\n",
      "模型输出结果: 差评\n"
     ]
    }
   ],
   "source": [
    "sentence = \"包装压坏了，里面的东西也坏了，怎么办\"\n",
    "model.eval()\n",
    "with torch.inference_mode():\n",
    "    inputs = tokenizer(sentence, return_tensors='pt')\n",
    "    if torch.cuda.is_available():\n",
    "        inputs = {k: v.cuda() for k, v in inputs.items()}\n",
    "    logits = model(**inputs).logits\n",
    "    pred = torch.argmax(logits, axis=-1)\n",
    "    print(f\"输入: {sentence}\\n模型输出结果: {model.config.id2label[pred.item()]}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [],
   "source": [
    "from transformers import pipeline\n",
    "pipe = pipeline(\"text-classification\", model=model, tokenizer=tokenizer, device=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "397\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[{'label': '好评', 'score': 0.9778811931610107}]"
      ]
     },
     "execution_count": 66,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# max_position_embedding = 512, 所以输入序列最长不能超过512\n",
    "sentence = \"包装压坏了，里面的东西也坏了，怎么办，你处理的好的话，我就给你好评，包装压坏了，里面的东西也坏了，怎么办，你处理的好的话，我就给你好评包装压坏了，里面的东西也坏了，怎么办，你处理的好的话，我就给你好评包装压坏了，里面的东西也坏了，怎么办，你处理的好的话，我就给你好评包装压坏了，里面的东西也坏了，怎么办，你处理的好的话，我就给你好评包装压坏了，里面的东西也坏了，怎么办，你处理的好的话，我就给你好评包装压坏了，里面的东西也坏了，怎么办，你处理的好的话，我就给你好评包装压坏了，里面的东西也坏了，怎么办，你处理的好的话，我就给,包装压坏了，里面的东西也坏了，怎么办，你处理的好的话，我就给你好评，包装压坏了，里面的东西也坏了，怎么办，你处理的好的话，我就给你好评包装压坏了，里面的东西也坏了，怎么办，你处理的好的话，我就给你好评包装压坏了，里面的东西也坏了，怎么办，你处理的好的话，我就给你好评包\"\n",
    "print(len(sentence))\n",
    "pipe(sentence)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "torch2.4",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
